// TBlockHashMap.h
//
// The hash map for TBlock & its derived classes
// Created @ 07-07-01

#ifndef TBLOCKHASHMAP_H
#define TBLOCKHASHMAP_H

#include "crossbit/TBlock.h"
#include "crossbit/VBlock.h"
#include "crossbit/common.h"
#include "string.h"
#include <iostream>

namespace crossbit{

	class HashMap{
		// Bucket
		public:
			class Bucket{
				public:
					XTMemAddr sc_addr;
					TBlock* ptrTBlock;
					VBlock* ptrVBlock;
					//void* ptrData;
					Bucket* next;
					bool valid;
				public:
					Bucket(XTMemAddr addr = -1,
							TBlock* tData = NULL,
							VBlock* vData = NULL,
							Bucket* next = NULL,
							bool valid = false
					      ):
						sc_addr(addr),
						ptrTBlock(tData),
						ptrVBlock(vData),
						next(next){
						}

					~Bucket(){
					}
			};

		public:
			HashMap(MemoryManager *mm, XTUint32 n = 0x00010000): totalBuckets_(n), bk_id(0){
				MemoryManager	*hm_mm = mm;
				XTUint32	mm_bk_size = n * sizeof(Bucket);
				hashMap_ = new ((Bucket *) hm_mm->allocateObjectPool(&bk_id , mm_bk_size, mm_bk_size)) Bucket[n];

				//hashMap_ = new Bucket[n];
				//memset(hashMap_, 0, n*sizeof(Bucket));
				mask_ = totalBuckets_ - 1;

				XTUint32 tmpmask = mask_;
				XTInt32 maxbit = 0;
				XTInt32 i = 0;

				for (; i < 32 ; ++i){
					if (mask_ & 0x1 == 0x1)	maxbit = i;
					mask_ = mask_ >> 1;
				}
				mask_ = 0x1;
				for (i = 0; i < maxbit; ++i)	    mask_ = (mask_ << 1) | 0x1;
				while (mask_ > tmpmask)	    mask_ = mask_ >> 1;
			}

			~HashMap(){
				//Clear();
				// Delete bucket table
				//delete [] hashMap_;
			}

		public:
			void InsertTBlock(XTMemAddr spc, TBlock* p){

				Bucket* curBucket = Find(spc);

				curBucket -> ptrTBlock = p;

			}

			void InsertVBlock(XTMemAddr spc, VBlock* p){

				Bucket* curBucket = Find(spc);

				curBucket -> ptrVBlock = p;

			}
		private:
			inline Bucket* Find(XTMemAddr spc){
				Bucket* curBucket = hashMap_ + (spc & mask_);

				if (curBucket->sc_addr == -1)
				{

					curBucket->sc_addr=spc;
					return curBucket;

				}
				else if (curBucket->sc_addr == spc)
					return curBucket;

				else{ 

					while(curBucket->next != NULL){

						curBucket = curBucket -> next;
						if (curBucket -> sc_addr == spc)
							return curBucket;

					}
				}

				Bucket* newBucket = new Bucket(spc,NULL,NULL,NULL);

				curBucket -> next = newBucket;

				return newBucket;
			}

		public:
			TBlock* FindTBlock(XTMemAddr spc){
				Bucket* curBucket = Find(spc);
				return curBucket -> ptrTBlock;
			}

			VBlock* FindVBlock(XTMemAddr spc){
				Bucket* curBucket = Find(spc);
				return curBucket -> ptrVBlock;
			}

			void Delete(XTMemAddr spc){

				XTInt32 pos = spc & mask_;//Hash(spc);
				Bucket* curBucket = hashMap_ + pos;
				Bucket* nextBucket = NULL;

				if (curBucket -> sc_addr == -1)		return;


				// If found bucket on the table
				if (curBucket -> sc_addr == spc){
					if (curBucket -> next == NULL){
						if( curBucket -> ptrVBlock != NULL )
							delete curBucket -> ptrVBlock;
						if( curBucket -> ptrTBlock != NULL )
							delete curBucket -> ptrTBlock;
						memset(curBucket, 0, sizeof(Bucket));
					}
					else{

						nextBucket = curBucket -> next;
						curBucket -> sc_addr = nextBucket -> sc_addr;
						if( curBucket -> ptrVBlock != NULL )
							delete curBucket -> ptrVBlock;
						if( curBucket -> ptrTBlock != NULL )
							delete curBucket -> ptrTBlock;

						curBucket -> ptrTBlock = nextBucket -> ptrTBlock;
						curBucket -> ptrVBlock = nextBucket -> ptrVBlock;
						curBucket -> next = nextBucket -> next;
						// Cache is responsible for deleting these objects

						delete nextBucket;
					}
					return ;
				}
				// If not found on the table, search the linklist from
				// this bucket
				else{

					nextBucket = curBucket -> next;

					while (nextBucket != NULL){

						if (nextBucket -> sc_addr == spc){

							curBucket -> next = nextBucket -> next;
							//    delete nextBucket -> ptrTBlock -> vblock();

							delete nextBucket -> ptrTBlock;
							delete nextBucket -> ptrVBlock;
							delete nextBucket;

							return ;
						}
						else{

							curBucket = nextBucket;
							nextBucket = curBucket->next;
						}
					}
					return ;
				}
			}

		public:
			void Clear(){
				for (XTInt32 i = 0; i < totalBuckets_; i++){

					Bucket* curBucket = hashMap_ + i;
					// Delete LinkList from this bucket

					if (curBucket -> sc_addr != -1){

						delete curBucket -> ptrTBlock;
						delete curBucket -> ptrVBlock;

						curBucket = curBucket -> next;
						Bucket* nextBucket = NULL;

						while (curBucket != NULL){

							nextBucket = curBucket -> next;
							//  delete curBucket -> ptrTBlock_ -> vblock();
							delete curBucket -> ptrTBlock;
							delete curBucket -> ptrVBlock;
							delete curBucket;

							curBucket = nextBucket;
						}
					} 
				}
				memset(reinterpret_cast<XTUint8*>(hashMap_), 0, totalBuckets_ * sizeof(Bucket));
			}
			/*
			   public:
			   void ClearTBlocks(){
			   XTInt32 i = 0;
			   Bucket* curBucket;
			   for (;i < totalBuckets_; i++){
			   curBucket = hashMap_ + i;
			   if (curBucket -> valid == true){
			   delete (TBlock*)(curBucket -> ptrData);
			   curBucket -> valid = false;

			   if (curBucket -> next == NULL)
			   continue;

			   Bucket* nextBucket = curBucket -> next_;
			   while (nextBucket != NULL){
			   curBucket = nextBucket;
			   nextBucket = curBucket -> next_;
			   delete (curBucket -> ptrTBlock_);
			   delete curBucket;
			   }
			   } 
			   }
			   }
			 */
		public:
			inline XTInt32 TotalBuckets(){
				return totalBuckets_;
			}

			// For debugging
		public:
			void Print(){
				XTInt32 i = 0;
				for (;i < totalBuckets_; i++){
					Bucket* curBucket = hashMap_ + i;
					// Delete LinkList from this bucket
					if (curBucket -> sc_addr == -1){
						std::cout << "Bucket 0x" << std::hex << curBucket -> sc_addr
							<< "(" << std::hex << (unsigned int)curBucket -> ptrTBlock
							<< ")";
						curBucket = curBucket -> next;
						while (curBucket != NULL){
							std::cout << " --> 0x" << std::hex << curBucket -> sc_addr
								<< "(" << std::hex << (unsigned int)curBucket -> ptrTBlock
								<< ")";
							curBucket = curBucket -> next;
						}
						std::cout << std::endl;
					} 
				}
			}

		private:
			XTUint32	bk_id;
			Bucket* hashMap_;
			XTUint32 totalBuckets_;
			XTUint32  mask_;
	};

} // End of namespace crossbit
#endif
